// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "adjacency_matrix.h"

#include "verbose.h"

#include <vector>

template <typename DerivedF, typename T>
IGL_INLINE void igl::adjacency_matrix(
  const Eigen::MatrixBase<DerivedF> & F,
  Eigen::SparseMatrix<T>& A)
{
  typedef typename DerivedF::Scalar Index;

  typedef Eigen::Triplet<T> IJV;
  std::vector<IJV > ijv;
  ijv.reserve(F.size()*2);
  // Loop over **simplex** (i.e., **not quad**)
  for(int i = 0;i<F.rows();i++)
  {
    // Loop over this **simplex**
    for(int j = 0;j<F.cols();j++)
    for(int k = j+1;k<F.cols();k++)
    {
      // Get indices of edge: s --> d
      Index s = F(i,j);
      Index d = F(i,k);
      ijv.push_back(IJV(s,d,1));
      ijv.push_back(IJV(d,s,1));
    }
  }

  const Index n = F.maxCoeff()+1;
  A.resize(n,n);
  switch(F.cols())
  {
    case 3:
      A.reserve(6*(F.maxCoeff()+1));
      break;
    case 4:
      A.reserve(26*(F.maxCoeff()+1));
      break;
  }
  A.setFromTriplets(ijv.begin(),ijv.end());

  // Force all non-zeros to be one

  // Iterate over outside
  for(int k=0; k<A.outerSize(); ++k)
  {
    // Iterate over inside
    for(typename Eigen::SparseMatrix<T>::InnerIterator it (A,k); it; ++it)
    {
      assert(it.value() != 0);
      A.coeffRef(it.row(),it.col()) = 1;
    }
  }
}

template <typename DerivedI, typename DerivedC, typename T>
IGL_INLINE void igl::adjacency_matrix(
  const Eigen::MatrixBase<DerivedI> & I,
  const Eigen::MatrixBase<DerivedC> & C,
  Eigen::SparseMatrix<T>& A)
{
  typedef Eigen::Triplet<T> IJV;
  std::vector<IJV > ijv;
  ijv.reserve(C(C.size()-1)*2);
  typedef typename DerivedI::Scalar Index;
  const Index n = I.maxCoeff()+1;
  {
    // loop over polygons
    for(Index p = 0;p<C.size()-1;p++)
    {
      // number of edges
      const Index np = C(p+1)-C(p);
      // loop over edges
      for(Index c = 0;c<np;c++)
      {
        const Index i = I(C(p)+c);
        const Index j = I(C(p)+((c+1)%np));
        ijv.emplace_back(i,j,1);
        ijv.emplace_back(j,i,1);
      }
    }
  }

  A.resize(n,n);
  A.reserve(6*n);
  A.setFromTriplets(ijv.begin(),ijv.end());

  // Force all non-zeros to be one

  // Iterate over outside
  for(int k=0; k<A.outerSize(); ++k)
  {
    // Iterate over inside
    for(typename Eigen::SparseMatrix<T>::InnerIterator it (A,k); it; ++it)
    {
      assert(it.value() != 0);
      A.coeffRef(it.row(),it.col()) = 1;
    }
  }
}

#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, 3, 1, -1, 3>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3>> const&, Eigen::SparseMatrix<int, 0, int>&);
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<int, 0, int>& );
// generated by autoexplicit.sh
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, -1, 0, -1, -1>, bool>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<bool, 0, int>&);
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<int, 0, int>&);
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, 3, 0, -1, 3>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::SparseMatrix<int, 0, int>&);
#endif
